package com.dgut.leave.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dgut.leave.dao.LeaveRepository;
import com.dgut.leave.entity.Leave;
import com.dgut.leave.entity.LeaveQueryDTO;

@Service
@Transactional
public class LeaveService implements ILeaveService {
	@Autowired
	private LeaveRepository leaveRepository;

	// 流程服务
	@Autowired
	private IdentityService identityService;
	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;
	@Autowired
	private RepositoryService repositoryService;

	@Override
	public void save(Leave leave, String status) {
		// Staff staff = staffService.findByStaffName(leave.getUserId());
		// Position position = positionService.findByPosName(staff.getPosition());
		leave.setStatus(status);
		leaveRepository.save(leave);
	}

	@Override
	public void delete(Long id) {
		Leave leave = leaveRepository.findOne(id);
		if (leave != null) {
			leaveRepository.delete(leave);
		}
	}

	@Override
	@Transactional(readOnly = true)
	public Leave findOne(Long id) {
		return leaveRepository.findOne(id);
	}

	@Override
	@Transactional(readOnly = true)
	public Page<Leave> findLeave(String userId, Pageable pageable) {
		return leaveRepository.findLeave(userId, pageable);
	}

	@Transactional(readOnly = true)
	@Override
	public Page<Leave> findPage(Specification<Leave> spec, Pageable pageable) {
		return leaveRepository.findAll(spec, pageable);
	}

	/*----------------------------------------------流程业务--------------------------------------------*/
	@Override
	public ProcessInstance startWorkflow(Long leaveId, Map<String, Object> variables) {
		// 1.声明流程实例
		ProcessInstance processInstance = null;
		// 2.获取创建好的请假实例
		Leave leave = leaveRepository.findOne(leaveId);
		if (leave != null) {
			try {

				// 3.授权
				identityService.setAuthenticatedUserId(leave.getUserId());
				// 4.把entityid转换为业务主键(用于工作流程实例关联业务)
				String businessKey = leave.getId().toString();
				// 5.启动流程实例:processDefinitionKey, businessKey, variables
				processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables);
				// 6.业务实体与流程实例关联
				leave.setProcessInstanceId(processInstance.getId());
				leave.setApplyTime(new Date());
				// 7.更新到数据库
				// leaveRepository.save(leave);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				// 8.取消授权
				identityService.setAuthenticatedUserId(null);
			}
		}
		return processInstance;
	}

	// 查询任务
	@Override
	public Page<LeaveQueryDTO> findTodoTasks(String userId, Pageable pageable) {
		List<LeaveQueryDTO> results = new ArrayList<LeaveQueryDTO>();
		// 根据当前人的查询
		TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateOrAssigned(userId);

		List<Task> tasks = taskQuery.list(); // .taskAssignee(""+userId).list();
		System.out.println(userId);
		System.out.println(tasks);// 根据流程的业务ID查询实体并关联
		for (Task task : tasks) {
			String processInstanceId = task.getProcessInstanceId();
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).active().singleResult();
			String businessKey = processInstance.getBusinessKey();
			if (businessKey == null) {
				continue;
			}
			Leave leave = leaveRepository.findOne(new Long(businessKey));
			if (leave != null) {
				LeaveQueryDTO leaveDTO = new LeaveQueryDTO();
				BeanUtils.copyProperties(leave, leaveDTO);
				leaveDTO.setTaskId(task.getId());
				leaveDTO.setTaskName(task.getName());
				leaveDTO.setTaskCreateTime(task.getCreateTime());
				leaveDTO.setAssignee(task.getAssignee());
				leaveDTO.setTaskDefinitionKey(task.getTaskDefinitionKey());
				leaveDTO.setSuspended(processInstance.isSuspended());
				ProcessDefinition processDefinition = getProcessDefinition(processInstance.getProcessDefinitionId());
				leaveDTO.setProcessDefinitionId(processDefinition.getId());
				leaveDTO.setVersion(processDefinition.getVersion());

				results.add(leaveDTO);
			}
		}
		// results List进行排序
		// 封装为Page返回
		return new PageImpl<LeaveQueryDTO>(results, pageable, results.size());
	}

	@Override
	public Page<LeaveQueryDTO> findRunningProcessInstaces(Page<Leave> page, int[] pageParams) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Page<LeaveQueryDTO> findFinishedProcessInstaces(Page<Leave> page, int[] pageParams) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 查询流程定义对象
	 *
	 * @param processDefinitionId
	 *            流程定义ID
	 * @return
	 */
	protected ProcessDefinition getProcessDefinition(String processDefinitionId) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
				.processDefinitionId(processDefinitionId).singleResult();
		return processDefinition;
	}

	/**
	 * 签收流程任务
	 *
	 * @param taskId
	 *            任务ID
	 * @param userId
	 *            签收人用户ID
	 * @return
	 */
	public void claim(String taskId, String userId) {
		taskService.claim(taskId, userId);

	}

	/**
	 * 完成流程任务
	 *
	 * @param taskId
	 *            任务ID
	 * @param variables
	 *            流程变量
	 * @return
	 */
	public void complete(String taskId, Map<String, Object> variables) {
		taskService.complete(taskId, variables);
	}

}
